/**
 * @file OrientedCircle.H
 * @brief 表示二维有向圆。曲线定向的左侧为曲线内部。
 * @author htli (3180102114@zju.edu.cn)
 * @version 1.0
 * @date 2022-03-12
 *
 * @copyright Copyright (c) 2022  linhuo2020
 *
 */
#ifndef _CIRCLE_H_
#define _CIRCLE_H_

#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>
#include "Core/Vec.h"

enum directionStyle
{
    Clockwise = -1,
    CounterClockwise = 1
};

class OrientedCircle
{
public:
    enum
    {
        Dim = 2
    };

    template <class T>
    using vector = std::vector<T>;
    using rVec = Vec<Real, Dim>;
    using iVec = Vec<int, Dim>;
    OrientedCircle(const rVec &aCenter,
                   const Real aRadius,
                   const directionStyle aDirection = Clockwise,
                   const Real atol = 1e-15) /*默认圆心在曲线外*/
        : center(aCenter), radius(aRadius), direction(aDirection), tolerance(atol)
    {
        assert(aRadius >= 0);
    };

protected:
    Real radius;
    rVec center;
    directionStyle direction;
    Real tolerance;

public:

    ///返回true曲线内部，返回false为外部及边界
    bool inEnclosure(const rVec &pos) const
    {
        const Real d = norm(pos - center);
        int flag = 0;
        if (d > (radius + tolerance))
            flag = direction;
        else if (std::abs(d - radius) <= tolerance)
            flag = 0;
        else
            flag = -direction;
        return (flag < 0);
    }

    vector<rVec> minimalEmbededdSquare() const
    {
        return (vector<rVec>){center - radius, center + radius, center - radius + (rVec){radius, 0}, center - radius + (rVec){0, radius}};
    }

    rVec polarRep(const Real rad) const
    {
        return center + (rVec){cos(rad), sin(rad)} * radius;
    }

    Real getRadian(const rVec &pos) const
    {
        rVec x = pos - center;
        return atan2(x[1], x[0]);
    }

    const vector<rVec> intersection2CartesianLine(int d, Real x_d) const
    {
        assert((x_d >= (center - radius)[d]) && (x_d <= (center + radius)[d]));
        Real delta2 = (radius * radius - (x_d - center[d]) * (x_d - center[d]));
        rVec middleP = rVec::unit(d) * x_d + rVec::unit(1 - d) * (center[1 - d]);
        if (delta2 < tolerance)
            return {middleP, middleP};
        else
            return {middleP + rVec::unit(1 - d) * sqrt(delta2), middleP - rVec::unit(1 - d) * sqrt(delta2)};
    }

    const rVec intersection2CartesianLine(int d, const rVec &x) const
    {
        bool isLowerPart = (x[1 - d] < center[1 - d]);
        return intersection2CartesianLine(d, x[d])[isLowerPart];
    }

    rVec getNormalGrad(const rVec &pos) const
    {
        return normalize((pos - center)) * (direction);
    };
};
#endif // !_CIRCLE_H_